﻿/**************************************************************
 *
 * 唯一标识：894157db-cc7e-4270-a6b5-3886b011f1a4
 * 命名空间：Microsoft.AspNetCore.Http
 * 创建时间：2023/8/8 16:49:43
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using MediatR;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.Mvc;
using Sgr.AspNetCore;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.AspNetCore.Http
{
    /// <summary>
    /// 扩展
    /// </summary>
    public static class HttpContextExtensions
    {
        private const string TokenErrorKey = "Token-Error";

        /// <summary>
        /// 设置令牌错误信息
        /// </summary>
        public static void SetTokenError(this HttpContext context, string errorType)
        {
            context.Items[TokenErrorKey] = errorType;
        }

        /// <summary>
        /// 清除令牌错误信息
        /// </summary>
        public static void ClearTokenError(this HttpContext context)
        {
            context.Items.Remove(TokenErrorKey);
        }

        /// <summary>
        /// 创建未授权访问的ProblemDetails对象
        /// </summary>
        /// <param name="context"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static ProblemDetails CreateUnauthorizedProblemDetails(
            this HttpContext context,
            string message = "")
        {
            string? tokenError = null;
            if (context.Items.TryGetValue(TokenErrorKey, out var error))
                tokenError = error?.ToString();

            var problemDetails = new ProblemDetails
            {
                Status = StatusCodes.Status401Unauthorized,
                Title = "未授权访问",
                Type = ProblemTypes.Unauthorized,
                Detail = string.IsNullOrEmpty(message) ? (tokenError?.GetDescription() ?? "未授权访问") : message,
                Instance = context.Request.Path
            };

            // 添加令牌相关的错误信息
            if (!string.IsNullOrEmpty(tokenError))
            {
                var oauthError = tokenError.ToOAuthErrorCode();
                problemDetails.Extensions["tokenError"] = oauthError;

                // 对过期的令牌添加特殊标记
                if (tokenError == TokenErrorType.Expired)
                {
                    problemDetails.Extensions["tokenExpired"] = true;
                }
            }

            return problemDetails;
        }

        /// <summary>
        /// 获取Http请求地址
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string GetRequestUrl(this HttpContext context)
        {
            var uriBuilder = new UriBuilder
            {
                Scheme = context.Request.Scheme,
                Host = context.Request.Host.Host,
                Path = context.Request.Path.ToString(),
                Query = context.Request.QueryString.ToString()
            };

            return uriBuilder.Uri.AbsolutePath;
        }

        /// <summary>
        /// 获取客户端IP地址
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string GetClientIpAddress(this HttpContext context)
        {
            try
            {
                string ip = context.GetCustomHeaderValue("X-Forwarded-For");

                if (string.IsNullOrWhiteSpace(ip))
                    ip = context.GetCustomHeaderValue("X-Real-IP");

                if (string.IsNullOrWhiteSpace(ip))
                    ip = $"{context?.Connection?.RemoteIpAddress}";

                return ip;
            }
            catch
            {
                return "0.0.0.0";
            }
        }

        /// <summary>
        /// 获取客户端硬件指纹
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string GetDeviceFingerprint(this HttpContext context)
        {
            return context.GetCustomHeaderValue("X-Device-Fingerprint");
        }

        /// <summary>
        /// 获取自定义请求头信息
        /// </summary>
        /// <param name="context"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetCustomHeaderValue(this HttpContext context, string key)
        {
            if (context.Request.Headers.TryGetValue(key, out var value) &&
                !string.IsNullOrWhiteSpace(value))
                return value.ToString();
            else
                return string.Empty;
        }

        ///// <summary>
        ///// 时间戳
        ///// </summary>
        //public string Timestamp { get; set; } = string.Empty;

        ///// <summary>
        ///// 随机数
        ///// </summary>
        //public string Nonce { get; set; } = string.Empty;

        ///// <summary>
        ///// 签名
        ///// </summary>
        //public string Signature { get; set; } = string.Empty;

        /// <summary>
        /// 获取用户申明信息
        /// </summary>
        /// <param name="context"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string? GetValueFromClaim(this HttpContext context, string key)
        {
            return context.User?.FindFirst(key)?.Value;
        }

        /// <summary>
        /// 获取用户申明信息
        /// </summary>
        /// <param name="context"></param>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetValueFromClaim(this HttpContext context, string key, string defaultValue)
        {
            var claim = context.User?.FindFirst(key);
            if (claim != null)
                return claim.Value;
            return defaultValue;
        }

        /// <summary>
        /// 获取请求表单信息
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task<string> GetHttpFormContentAsync(this HttpContext context)
        {
            if (context.Request.ContentType == null || context.Request.ContentType.Contains("multipart/form-data"))
                return "";

            string result = "";
            try
            {
                if (context.Request.HasFormContentType)
                {
                    var form = await context.Request.ReadFormAsync();
                    if (form != null)
                    {
                        StringBuilder stringBuilder = new();

                        foreach (var key in form)
                        {
                            stringBuilder.Append($"key:{key.Key} value:{key.Value}; ");
                        }

                        result = stringBuilder.ToString();
                    }
                }
            }
            catch { }

            return result;
        }
    }
}